﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description:  ViewDefResourcesContainerViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
using VmroleAuthor.Commands;

namespace VmroleAuthor.ViewModels
{
    public class ViewDefResourcesContainerViewModel : TreeViewItemViewModel, IDataErrorInfo, IProduceValidationResults, ISaveToDisk, IRemoveChildItem
    {     
        private readonly Dictionary<string, string> currentLocalizedParameters;
        private string newLocalizedResourceToBeAdded;
        private List<string> availableLocalizedRegionCodes;

        public static class PropertyNames
        {
            public const string Summary = "Summary";
            public const string NewLocalizedResourceToBeAdded = "NewLocalizedResourceToBeAdded";
        }

        public ViewDefResourcesContainerViewModel(ResourceDefinitionStorageInfo resourceDefinitionStorageInfo,ViewDefViewModel viewDefViewModel)
            : base(viewDefViewModel, true)
          {            
              this.ResourceDefinitionStorageInfo = resourceDefinitionStorageInfo;
              this.currentLocalizedParameters = new Dictionary<string, string>();
              this.AddLocalizedResourceCommand = new RelayCommand(
                 param => this.AddLocalizedResource((string)param),
                 param => this.CanAddLocalizedResource((string)param));
              this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
          }


        public string Summary
        {
            get { return "Resources"; }
        }

        public ResourceDefinitionStorageInfo ResourceDefinitionStorageInfo { get; private set; }

        public Dictionary<string, string> CurrentLocalizedParameters
        {
            get
            {        
                return this.currentLocalizedParameters;
            }
        }

        public List<string> AvailableLocalizedRegionCodes
        {
            get
            {
                if (this.availableLocalizedRegionCodes == null)
                {
                    this.availableLocalizedRegionCodes = new List<string>();
                    foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures))
                    {
                        this.availableLocalizedRegionCodes.Add(cultureInfo.Name);
                    }
                }
                return this.availableLocalizedRegionCodes;
            }
        }

        public string NewLocalizedResourceToBeAdded
        {
            get { return this.newLocalizedResourceToBeAdded; }
            set
            {
                this.newLocalizedResourceToBeAdded = value;
                this.OnPropertyChanged(PropertyNames.NewLocalizedResourceToBeAdded);
            }
        }

        public ICommand AddLocalizedResourceCommand
        {
            get;
            private set;
        }

        public bool CanAddLocalizedResource(string languageCode)
        {
            if (string.IsNullOrEmpty(languageCode))
            {
                return false;
            }
            this.IsExpanded = true;
            bool dupe = this.Children.OfType<ViewDefResourcesViewModel>().Any(resourcesViewModel => string.Equals(languageCode, resourcesViewModel.LanguageCode, StringComparison.OrdinalIgnoreCase));
            if (dupe)
            {
                return false;
            }
            // Validate that the language code is valid like en-us
            try
            {               
                var test = new RegionInfo(languageCode);
            }
            catch (ArgumentException)
            {
                // The code was not a valid country/region code for the specified language
                return false;
            }
            return true;
        }

        public void AddLocalizedResource(string languageCode)
        {
            this.IsExpanded = true;
            string resourcesFileName = System.IO.Path.Combine(this.ResourceDefinitionStorageInfo.WorkingDir, languageCode, "1.resources");
            var resViewModel = new ViewDefResourcesViewModel(resourcesFileName, languageCode, this);
            this.Children.Add(resViewModel);
            resViewModel.IsSelected = true;
            this.NewLocalizedResourceToBeAdded = null;
        }

        public List<string> AvailableLocalizedPropertyValues
        {
            get
            {
                //TODO:
                List<string> availableLocalizedPropertyValues = new List<string>();
                availableLocalizedPropertyValues.Add(ViewDefViewModel.AutoLocalizeMoniker);
                return availableLocalizedPropertyValues;
            }
        }

        public bool ContainsLocalizableParameter(string parameterName)
        {
            // across all languages
            bool containsLocalizableParameter = true;
            foreach (TreeViewItemViewModel treeViewItemViewModel in this.Children)
            {
                var resourcesViewModel = treeViewItemViewModel as ViewDefResourcesViewModel;
                if (resourcesViewModel != null)
                {
                    containsLocalizableParameter = resourcesViewModel.ContainsLocalizableParameter(parameterName);
                    if (!containsLocalizableParameter)
                    {
                        break;
                    }
                }
            }
            return containsLocalizableParameter;
        }

        public void AddLocalizableParameterIfNotExist(string parameterName, Func<string> optionalInitialValueGetter = null)
        {
            if (parameterName != null && !this.currentLocalizedParameters.ContainsKey(parameterName))
            {
                this.currentLocalizedParameters.Add(parameterName, optionalInitialValueGetter != null ? optionalInitialValueGetter() : string.Empty);
            }
            foreach (TreeViewItemViewModel treeViewItemViewModel in this.Children)
            {
                var resourcesViewModel = treeViewItemViewModel as ViewDefResourcesViewModel;
                if (resourcesViewModel != null)
                {
                    resourcesViewModel.AddLocalizableParameterIfNotExist(parameterName, optionalInitialValueGetter != null ? optionalInitialValueGetter() : string.Empty);
                }
            }
        }

        public void RemoveLocalizableParameterIExists(string parameterName)
        {
            if (parameterName != null && this.currentLocalizedParameters.ContainsKey(parameterName))
            {
                this.currentLocalizedParameters.Remove(parameterName);
            }
            foreach (TreeViewItemViewModel treeViewItemViewModel in this.Children)
            {
                var resourcesViewModel = treeViewItemViewModel as ViewDefResourcesViewModel;
                if (resourcesViewModel != null)
                {
                    resourcesViewModel.RemoveLocalizableParameterIfExists(parameterName);
                }
            }
        }

        public void SaveToDisk()
        {
            if (this.ResourceDefinitionStorageInfo != null)
            {               
                this.IsExpanded = true;
                foreach (TreeViewItemViewModel treeViewItemViewModel in this.Children)
                {
                    var resourcesViewModel = treeViewItemViewModel as ViewDefResourcesViewModel;
                    if (resourcesViewModel != null)
                    {
                        resourcesViewModel.SaveToDisk();
                    }
                }
            }
            else
            {
                MessageBox.Show(string.Format("Unable to save resources in package. Storage Info not set"), "Save VmRole Resource Definition Package");
            }
        }

        protected override void LoadChildren()
        {           
            if (this.ResourceDefinitionStorageInfo.ResourceFileNames != null)
            {
                // Evaluate all properties
                foreach (TreeViewItemViewModel childItem in Children)
                {
                    var viewDefSectionViewModel = childItem as ViewDefSectionViewModel;
                    if (viewDefSectionViewModel != null)
                    {
                        //var title = viewDefSectionViewModel.Title;
                        viewDefSectionViewModel.IsExpanded = true;
                        foreach (TreeViewItemViewModel categoryItem in viewDefSectionViewModel.Children)
                        {
                            var categoryViewModel = categoryItem as ViewDefCategoryViewModel;
                            if (categoryViewModel != null)
                            {
                                //var categoryName = categoryViewModel.CategoryName;
                                categoryViewModel.IsExpanded = true;
                                foreach (var parameterViewModel in categoryViewModel.ViewDefParameterViewModels)
                                {
                                    var d0 = parameterViewModel.Label;
                                    var d1 = parameterViewModel.Description;
                                    var d2 = parameterViewModel.DefaultValue;
                                    var d3 = parameterViewModel.DefaultValue;
                                    var d4 = parameterViewModel.NewTagToBeAdded;
                                    var d5 = parameterViewModel.ImageTags;
                                    var d6 = parameterViewModel.ValidationRequired;
                                    var d7 = parameterViewModel.ValidationMinLength;
                                    var d8 = parameterViewModel.ValidationMaxLength;
                                    var d9 = parameterViewModel.ValidationRegExp;
                                    var d10 = parameterViewModel.ValidationMinRange;
                                    var d11 = parameterViewModel.ValidationMaxRange;
                                    var d12 = parameterViewModel.ValidationMessageRequired;
                                    var d13 = parameterViewModel.ValidationMessageLength;
                                    var d14 = parameterViewModel.ValidationMessageRegExp;
                                    var d15 = parameterViewModel.ValidationMessageRange;
                                }
                            }
                        }
                    }
                }
                foreach (string resourceFileName in this.ResourceDefinitionStorageInfo.ResourceFileNames)
                {
                    string languageCode = GetLanguageCode(resourceFileName);
                    if (!string.IsNullOrEmpty(languageCode))
                    {
                        //load resource file view model   
                        try
                        {
                            this.Children.Add(new ViewDefResourcesViewModel(resourceFileName, languageCode, this));
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(string.Format("Unable to load resources json {0} found in the package. Exception {1}. Ignoring loading it", resourceFileName, ex.Message), "Open VmRole Resource Definition Package");
                        }
                    }
                }
            }
        }

        public void RemoveChild(TreeViewItemViewModel childItem)
        {          
            var resourcesViewModel = childItem as ViewDefResourcesViewModel;
            if (resourcesViewModel != null)
            {
                if ((resourcesViewModel.ResourceFileName != null) && File.Exists(resourcesViewModel.ResourceFileName))
                {
                    File.Delete(resourcesViewModel.ResourceFileName);
                }
                this.Children.Remove(childItem);
            }
        }

        private string GetLanguageCode(string resourceFileName)
        {
            var separators = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
            string fullFolderPath = Path.GetFullPath(resourceFileName).TrimEnd('\\');
            var entries = fullFolderPath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
            if (entries.Length == 0)
            {
                // "Incorrect directory specified";
                return null;
            }
            string foldername = null;
            if (entries.Length >= 2)
            {
                foldername = entries[entries.Length - 2];
            }
            return foldername;
        }

        public string this[string propertyName]
        {
            get
            {
                switch (propertyName)
                {
                    case PropertyNames.NewLocalizedResourceToBeAdded:
                        if (!string.IsNullOrEmpty(this.NewLocalizedResourceToBeAdded))
                        {
                            bool dupe =
                                this.Children.OfType<ViewDefResourcesViewModel>()
                                    .Any(
                                        resourcesViewModel =>
                                        string.Equals(this.NewLocalizedResourceToBeAdded,
                                                      resourcesViewModel.LanguageCode,
                                                      StringComparison.OrdinalIgnoreCase));
                            if (dupe)
                            {
                                return "Duplicate language code";
                            }
                            // Validate that the language code is valid like en-us
                            try
                            {
                                new CultureInfo(this.NewLocalizedResourceToBeAdded);
                            }
                            catch (ArgumentException)
                            {
                                // The code was not a valid country/region code for the specified language
                                return "Invalid language code";
                            }
                        }
                        break;                
                }
                return null;
            }
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error           
        }     

    }
}
